﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Data;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using ZoneFiveSoftware.Common.Data.Fitness;
using ZoneFiveSoftware.Common.Data.Measurement;
using ZoneFiveSoftware.Common.Visuals;
using ZoneFiveSoftware.Common.Visuals.Fitness;
using STCommon.Controller;
using STCommon.View;
using STCommon.Data;
using STCommon.Resources;
using DistributionPlugin.Controller;
using DistributionPlugin.Data;

namespace DistributionPlugin.View
{
    public partial class DistributionReportsControl : UserControl
    {
        public DistributionReportsControl(IActivityReportsView reportView)
        {
            InitializeComponent();

            // Setup all control arrays
            m_SingleChartPanels[0] = SingleChartPanel1;
            m_SingleChartPanels[1] = SingleChartPanel2;
            m_SingleChartPanels[2] = SingleChartPanel3;
            m_SingleChartPanels[3] = SingleChartPanel4;

            m_HeaderPanels[0] = HeaderPanel1;
            m_HeaderPanels[1] = HeaderPanel2;
            m_HeaderPanels[2] = HeaderPanel3;
            m_HeaderPanels[3] = HeaderPanel4;

            m_ListModeButtons[0] = ListModeButton1;
            m_ListModeButtons[1] = ListModeButton2;
            m_ListModeButtons[2] = ListModeButton3;
            m_ListModeButtons[3] = ListModeButton4;

            m_ChartModeButtons[0] = ChartModeButton1;
            m_ChartModeButtons[1] = ChartModeButton2;
            m_ChartModeButtons[2] = ChartModeButton3;
            m_ChartModeButtons[3] = ChartModeButton4;

            m_SetupControls[0] = DistributionSetupControl1;
            m_SetupControls[1] = DistributionSetupControl2;
            m_SetupControls[2] = DistributionSetupControl3;
            m_SetupControls[3] = DistributionSetupControl4;

            m_BarCharts[0] = DistributionBarChart1;
            m_BarCharts[1] = DistributionBarChart2;
            m_BarCharts[2] = DistributionBarChart3;
            m_BarCharts[3] = DistributionBarChart4;

            m_BarChartPanels[0] = DistributionBarChartPanel1;
            m_BarChartPanels[1] = DistributionBarChartPanel2;
            m_BarChartPanels[2] = DistributionBarChartPanel3;
            m_BarChartPanels[3] = DistributionBarChartPanel4;

            m_TreeLists[0] = DistributionTreeList1;
            m_TreeLists[1] = DistributionTreeList2;
            m_TreeLists[2] = DistributionTreeList3;
            m_TreeLists[3] = DistributionTreeList4;

            m_ChartHeaderActionBanners[0] = ChartHeaderActionBanner1;
            m_ChartHeaderActionBanners[1] = ChartHeaderActionBanner2;
            m_ChartHeaderActionBanners[2] = ChartHeaderActionBanner3;
            m_ChartHeaderActionBanners[3] = ChartHeaderActionBanner4;

            Debug.Assert(reportView != null);
            m_ReportView = reportView;
            m_ReportView.PropertyChanged += new PropertyChangedEventHandler(ReportView_PropertyChanged);
            CurrentReport = m_ReportView.ActiveReport;

            ReportPageOptions.Instance.OptionChanged += new PropertyChangedEventHandler(OnOptionChanged);
            for (int i = 0; i < ReportPageOptions.MaxPanelCount; ++i)
            {
                ReportPageOptions.Instance.GetPanelOptions(i).OptionChanged += new PropertyChangedEventHandler(OnOptionChanged);

                m_ListModeButtons[i].CenterImage = STCommon.Resources.Resources.ReportList;
                m_ChartModeButtons[i].CenterImage = STCommon.Resources.Resources.ReportBarCharts;

                m_SetupControls[i].LabelProvider = new ReportsLabelUnitProvider(this, i);
                m_SetupControls[i].Options = ReportPageOptions.Instance.GetPanelOptions(i);
                m_BarCharts[i].LabelProvider = new ReportsLabelUnitProvider(this, i);

                int defaultColumnWidth = m_TreeLists[i].Size.Width / 5;
                m_TreeLists[i].Columns.Add(new TreeList.Column("Range", CommonResources.Text.LabelRange, defaultColumnWidth, StringAlignment.Near));
                m_TreeLists[i].Columns.Add(new TreeList.Column("TimePercent", TextResourceManager.TimePercentText, defaultColumnWidth, StringAlignment.Center));
                m_TreeLists[i].Columns.Add(new TreeList.Column("DistancePercent", TextResourceManager.DistancePercentText, defaultColumnWidth, StringAlignment.Center));
                m_TreeLists[i].Columns.Add(new TreeList.Column("TotalTime", CommonResources.Text.LabelTotalTime, defaultColumnWidth, StringAlignment.Center));
                m_TreeLists[i].Columns.Add(new TreeList.Column("TotalDistance", CommonResources.Text.LabelTotalDistance, defaultColumnWidth, StringAlignment.Center));
                m_TreeLists[i].NumLockedColumns = 1;
                m_TreeLists[i].LabelProvider = new DistributionLabelProvider(new ReportsLabelUnitProvider(this, i));
                ReportPageOptions.Instance.GetPanelOptions(i).TreeListSerializer.TreeList = m_TreeLists[i];
            }

            // Fake option changed to update UI
            OnOptionChanged(this, null);
        }

        private void ActiveReport_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Activities")
            {
                UpdateReportActivities();
            }
        }

        void ActiveReport_BeforeSave(object sender, EventArgs e)
        {
            ReportPageOptions.Instance.SaveToReport(CurrentReport);
        }

        private void ReportView_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "ActiveReport")
            {
                CurrentReport = m_ReportView.ActiveReport;
            }
        }

        private void OnActivityDataChanged(object sender, PropertyChangedEventArgs e)
        {
            // Fake an update of selected activities.  This refreshes everything.
            UpdateReportActivities();
        }

        private void OnOptionChanged(object sender, PropertyChangedEventArgs e)
        {
            for (int i = 0; i < ReportPageOptions.MaxPanelCount; ++i)
            {
                System.Windows.Forms.Panel panelControl = m_SingleChartPanels[i];

                panelControl.Visible = i < ReportPageOptions.Instance.DisplayedPanelsCount;

                if (panelControl.Visible)
                {
                    ReportOptions currentPanelOptions = ReportPageOptions.Instance.GetPanelOptions(i);

                    m_BarCharts[i].Referential = currentPanelOptions.SelectedReferential;

                    m_ListModeButtons[i].Selected = currentPanelOptions.IsInListMode;
                    m_ChartModeButtons[i].Selected = !currentPanelOptions.IsInListMode;
                    m_TreeLists[i].Visible = currentPanelOptions.IsInListMode;
                    m_BarChartPanels[i].Visible = !currentPanelOptions.IsInListMode;
                }
            }

            // Setup column & row span based on displayed panels
            MainTableLayoutPanel.SetColumnSpan(m_SingleChartPanels[0],
                                                ReportPageOptions.Instance.DisplayedPanelsCount <= 2 ? 2 : 1);
            MainTableLayoutPanel.SetRowSpan(m_SingleChartPanels[0],
                                            ReportPageOptions.Instance.DisplayedPanelsCount == 1 ? 2 : 1);
            MainTableLayoutPanel.SetColumnSpan(m_SingleChartPanels[1],
                                                ReportPageOptions.Instance.DisplayedPanelsCount <= 3 ? 2 : 1);

            if (ReportPageVisible)
            {
                if (sender is ReportOptions)
                {
                    int optionsIndex = ReportPageOptions.Instance.GetPanelOptionsIndex(sender as ReportOptions);

                    if (optionsIndex < ReportPageOptions.Instance.DisplayedPanelsCount)
                    {
                        UpdateDistributionChart(optionsIndex);
                    }
                }
                else
                {
                    UpdateDistributionCharts();
                }
            }
        }

#region UI callbacks

        private void DistributionSettingsControl_SizeChanged(object sender, EventArgs e)
        {
            // AutoSize is 1 refresh late so this patch fixes it.  Bug might be elsewhere,
            //  I just can't seem to find it
            Control resizedControl = sender as Control;
            int controlIndex = int.Parse((string)resizedControl.Tag) - 1;

            // Make sure the control completed initialization
            if (m_HeaderPanels[controlIndex] != null)
            {
                m_HeaderPanels[controlIndex].Size = new Size(m_HeaderPanels[controlIndex].Width,
                                                             resizedControl.Height);
            }
        }

        private void ViewHeaderActionBanner_LayoutButtonClick(object sender, EventArgs e)
        {
            ContextMenu menu = new ContextMenu();
            IconizedSTMenuItem menuItem;

            // 1 Chart
            menuItem = new IconizedSTMenuItem(PluginMain.GetApplication().VisualTheme,
                                              null,
                                              new EventHandler(LayoutMenuEventHandler),
                                              STCommon.Resources.Resources.ReportLayout1Item,
                                              STCommon.Resources.Resources.ReportLayout1Item);
            menuItem.Tag = 1;
            menuItem.Selected = ReportPageOptions.Instance.DisplayedPanelsCount == 1;
            menu.MenuItems.Add(menuItem);

            // 2 Charts
            menuItem = new IconizedSTMenuItem(PluginMain.GetApplication().VisualTheme,
                                              null,
                                              new EventHandler(LayoutMenuEventHandler),
                                              STCommon.Resources.Resources.ReportLayout2Items,
                                              STCommon.Resources.Resources.ReportLayout2Items);
            menuItem.Tag = 2;
            menuItem.Selected = ReportPageOptions.Instance.DisplayedPanelsCount == 2;
            menu.MenuItems.Add(menuItem);

            // 3 Charts
            menuItem = new IconizedSTMenuItem(PluginMain.GetApplication().VisualTheme,
                                              null,
                                              new EventHandler(LayoutMenuEventHandler),
                                              STCommon.Resources.Resources.ReportLayout3Items,
                                              STCommon.Resources.Resources.ReportLayout3Items);
            menuItem.Tag = 3;
            menuItem.Selected = ReportPageOptions.Instance.DisplayedPanelsCount == 3;
            menu.MenuItems.Add(menuItem);

            // 4 Charts
            menuItem = new IconizedSTMenuItem(PluginMain.GetApplication().VisualTheme,
                                              null,
                                              new EventHandler(LayoutMenuEventHandler),
                                              STCommon.Resources.Resources.ReportLayout4Items,
                                              STCommon.Resources.Resources.ReportLayout4Items);
            menuItem.Tag = 4;
            menuItem.Selected = ReportPageOptions.Instance.DisplayedPanelsCount == 4;
            menu.MenuItems.Add(menuItem);

            menu.Show(this, PointToClient(MousePosition));
        }

        public void LayoutMenuEventHandler(object sender, EventArgs args)
        {
            MenuItem clickedMenuItem = sender as MenuItem;
            ReportPageOptions.Instance.DisplayedPanelsCount = (int)clickedMenuItem.Tag;
        }

        private void ListViewButton_Click(object sender, EventArgs e)
        {
            Control clickedButton = sender as Control;
            ReportOptions currentPanelOptions = ReportPageOptions.Instance.GetPanelOptions(int.Parse((string)clickedButton.Tag));

            currentPanelOptions.IsInListMode = true;
        }

        private void ChartModeButton_Click(object sender, EventArgs e)
        {
            Control clickedButton = sender as Control;
            ReportOptions currentPanelOptions = ReportPageOptions.Instance.GetPanelOptions(int.Parse((string)clickedButton.Tag));

            currentPanelOptions.IsInListMode = false;
        }

        private void ChartHeaderActionBanner_MenuClicked(object sender, EventArgs e)
        {
            Control clickedButton = sender as Control;
            ReportOptions currentPanelOptions = ReportPageOptions.Instance.GetPanelOptions(int.Parse((string)clickedButton.Tag));
            ContextMenu menu = new ContextMenu();
            MenuItem menuItem;

            // Distance
            menuItem = new IconizedSTMenuItem(PluginMain.GetApplication().VisualTheme,
                                              CommonResources.Text.LabelDistance,
                                              new EventHandler(DistanceMenuEventHandler));
            menuItem.Checked = (currentPanelOptions.SelectedReferential == Enums.SportTracksXAxisReferential.Distance);
            menuItem.Tag = clickedButton.Tag;
            menu.MenuItems.Add(menuItem);

            // Time
            menuItem = new IconizedSTMenuItem(PluginMain.GetApplication().VisualTheme,
                                              CommonResources.Text.LabelTime,
                                              new EventHandler(TimeMenuEventHandler));
            menuItem.Checked = (currentPanelOptions.SelectedReferential == Enums.SportTracksXAxisReferential.Time);
            menuItem.Tag = clickedButton.Tag;
            menu.MenuItems.Add(menuItem);

            menu.Show(this, PointToClient(MousePosition));
        }

        public void DistanceMenuEventHandler(object sender, EventArgs args)
        {
            MenuItem clickedMenuItem = sender as MenuItem;
            ReportOptions currentPanelOptions = ReportPageOptions.Instance.GetPanelOptions(int.Parse((string)clickedMenuItem.Tag));

            currentPanelOptions.SelectedReferential = Enums.SportTracksXAxisReferential.Distance;
        }

        public void TimeMenuEventHandler(object sender, EventArgs args)
        {
            MenuItem clickedMenuItem = sender as MenuItem;
            ReportOptions currentPanelOptions = ReportPageOptions.Instance.GetPanelOptions(int.Parse((string)clickedMenuItem.Tag));

            currentPanelOptions.SelectedReferential = Enums.SportTracksXAxisReferential.Time;
        }

#endregion

        public void ThemeChanged(ITheme visualTheme)
        {
            ViewHeaderActionBanner.ThemeChanged(visualTheme);

            for(int i = 0; i < ReportPageOptions.MaxPanelCount; ++i)
            {
                m_TreeLists[i].ThemeChanged(visualTheme);
                m_BarCharts[i].ThemeChaged(visualTheme);
                m_ChartHeaderActionBanners[i].ThemeChanged(visualTheme);
            }
        }

        public void UICultureChanged(CultureInfo culture)
        {
            for (int i = 0; i < ReportPageOptions.MaxPanelCount; ++i)
            {
                m_SetupControls[i].UICultureChanged(culture);
            }
        }

        private void UnregisterActivityDataChangedHelpers()
        {
            foreach (ActivityDataChangedHelper helper in m_ActivityChangedHelpers)
            {
                helper.PropertyChanged -= new PropertyChangedEventHandler(OnActivityDataChanged);
            }

            m_ActivityChangedHelpers.Clear();
        }

        private void RegisterActivityDataChangedHelpers()
        {
            foreach (IActivity activity in ReportActivities)
            {
                ActivityDataChangedHelper newHelper = new ActivityDataChangedHelper(PluginMain.GetApplication(), activity);

                newHelper.PropertyChanged += new PropertyChangedEventHandler(OnActivityDataChanged);
                m_ActivityChangedHelpers.Add(newHelper);
            }
        }

        private void UpdateReportActivities()
        {
            ReportActivities = Utils.GetAllContainedUniqueItemsOfType<IActivity>(CurrentReport.Activities);

            // Refresh options speed referential
            for (int i = 0; i < ReportPageOptions.MaxPanelCount; ++i)
            {
                ReportPageOptions.Instance.GetPanelOptions(i).SpeedReferential = SpeedUnit;
            }

            // Refresh UI that depends on activity selection
            this.Enabled = ReportActivities.Count > 0;

            for(int i = 0; i < ReportPageOptions.MaxPanelCount; ++i)
            {
                m_SetupControls[i].Activities = ReportActivities;
            }

            if (ReportPageVisible)
            {
                UpdateDistributionCharts();
            }
        }

        private void UpdateDistributionChart(int index)
        {
            if (!m_bUpdatingChart)
            {
                m_bUpdatingChart = true;

                if (ReportPageVisible)
                {
                    IDictionary<INamedLowHighZone, DistributionZoneInfo> distributionResults = new Dictionary<INamedLowHighZone, DistributionZoneInfo>();

                    // Don't process when no activities selected
                    if (ReportActivities != null &&
                        ReportActivities.Count > 0)
                    {
                        ReportOptions panelOptions = ReportPageOptions.Instance.GetPanelOptions(index);
                        IZoneCategory tempZoneCategory = Utils.CreateUnregisteredZoneCategory(PluginMain.GetApplication().Logbook);

                        DataProcessing.FillZoneCategoryForActivitiesAndOptionsHelper(ReportActivities,
                                                                                        panelOptions,
                                                                                        tempZoneCategory);
                        distributionResults = DataProcessing.GetCumulativeInfoForActivities(ReportActivities,
                                                                                            panelOptions,
                                                                                            tempZoneCategory);

                        if (panelOptions.IsInListMode)
                        {
                            m_TreeLists[index].RowData = distributionResults.Values;
                        }
                        else
                        {
                            m_BarCharts[index].DistributionData = distributionResults.Values;
                        }
                    }
                    else
                    {
                        m_TreeLists[index].RowData = null;
                        m_BarCharts[index].DistributionData = null;
                    }
                }

                m_bUpdatingChart = false;
            }
        }

        private void UpdateDistributionCharts()
        {
            for (int i = 0; i < ReportPageOptions.Instance.DisplayedPanelsCount; ++i)
            {
                UpdateDistributionChart(i);
            }
        }

        private Speed.Units SpeedUnit
        {
            get
            {
                Length.Units distanceUnit;
                Speed.Units speedUnit;

                Utils.GetCommonDistanceUnitForActivities(ReportActivities, PluginMain.GetApplication(),
                                                         out distanceUnit, out speedUnit);

                return speedUnit;
            }
        }

        public IList<IActivity> ReportActivities
        {
            get { return m_ReportActivities; }
            private set
            {
                if (ReportActivities != value)
                {
                    UnregisterActivityDataChangedHelpers();

                    m_ReportActivities = value;

                    RegisterActivityDataChangedHelpers();
                }
            }
        }

        public bool ReportPageVisible
        {
            get { return m_ReportPageVisible; }
            set
            {
                if (ReportPageVisible != value)
                {
                    m_ReportPageVisible = value;

                    if (ReportPageVisible)
                    {
                        UpdateDistributionCharts();
                    }
                }
            }
        }
        private IActivityReport CurrentReport
        {
            get { return m_CurrentReport; }
            set
            {
                if (CurrentReport != value)
                {
                    if (CurrentReport != null)
                    {
                        CurrentReport.PropertyChanged -= new PropertyChangedEventHandler(ActiveReport_PropertyChanged);
                        CurrentReport.BeforeSave -= new EventHandler(ActiveReport_BeforeSave);
                    }

                    m_CurrentReport = value;

                    if (CurrentReport != null)
                    {
                        CurrentReport.PropertyChanged += new PropertyChangedEventHandler(ActiveReport_PropertyChanged);
                        CurrentReport.BeforeSave += new EventHandler(ActiveReport_BeforeSave);
                    }

                    // Switch the updating chart flag to prevent update during settingsload.
                    m_bUpdatingChart = true;
                    ReportPageOptions.Instance.LoadFromReport(CurrentReport);
                    m_bUpdatingChart = false;

                    // Force update since we skipped them during settings load
                    UpdateReportActivities();
                }
            }
        }

        private IList<IActivity> m_ReportActivities = null;
        private List<ActivityDataChangedHelper> m_ActivityChangedHelpers = new List<ActivityDataChangedHelper>();
        private IActivityReportsView m_ReportView = null;
        private IActivityReport m_CurrentReport = null;
        private System.Windows.Forms.Panel[] m_SingleChartPanels = new System.Windows.Forms.Panel[ReportPageOptions.MaxPanelCount];
        private System.Windows.Forms.Panel[] m_HeaderPanels = new System.Windows.Forms.Panel[ReportPageOptions.MaxPanelCount];
        private ZoneFiveSoftware.Common.Visuals.Button[] m_ListModeButtons = new ZoneFiveSoftware.Common.Visuals.Button[ReportPageOptions.MaxPanelCount];
        private ZoneFiveSoftware.Common.Visuals.Button[] m_ChartModeButtons = new ZoneFiveSoftware.Common.Visuals.Button[ReportPageOptions.MaxPanelCount];
        private DistributionSetupControl[] m_SetupControls = new DistributionSetupControl[ReportPageOptions.MaxPanelCount];
        private DistributionBarChart[] m_BarCharts = new DistributionBarChart[ReportPageOptions.MaxPanelCount];
        private System.Windows.Forms.Panel[] m_BarChartPanels = new System.Windows.Forms.Panel[ReportPageOptions.MaxPanelCount];
        private ExtendedTreeList[] m_TreeLists = new ExtendedTreeList[ReportPageOptions.MaxPanelCount];
        private ActionBanner[] m_ChartHeaderActionBanners = new ActionBanner[ReportPageOptions.MaxPanelCount];
        private bool m_ReportPageVisible = false;
        private bool m_bUpdatingChart = false;
    }
}
